package de.dhbw.karlsruhe.picsim.gui;

import de.dhbw.karlsruhe.picsim.codeimport.LSTFile;
import de.dhbw.karlsruhe.picsim.codeimport.LSTLine;
import de.dhbw.karlsruhe.picsim.gui.data.OpCodeGui;
import de.dhbw.karlsruhe.picsim.model.cpu.ProgramCounter;
import de.dhbw.karlsruhe.picsim.model.memory.CommandRegisterAddress;
import de.dhbw.karlsruhe.picsim.model.memory.OpCode;
import de.dhbw.karlsruhe.picsim.model.memory.ProgramMemory;
import de.dhbw.karlsruhe.picsim.model.memory.impl.CommandRegisterAddressImpl;
import de.dhbw.karlsruhe.picsim.util.Bits;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: goesen
 * Date: Apr 13, 2010
 * Time: 11:29:39 PM
 */
public final class CommandRegisterImpl implements CommandRegister {
    private static final Log log = LogFactory.getLog(CommandRegisterImpl.class);
    private final Map<CommandRegisterAddress, String> comments;
    private final Set<Integer> breakPoints;

    private final ProgramMemory picMemory;
    private final ProgramCounter programCounter;

    public CommandRegisterImpl(final ProgramMemory picMemory, final LSTFile source,
                               final ProgramCounter programCounter) {
        this.picMemory = picMemory;
        this.programCounter = programCounter;
        breakPoints = new HashSet<Integer>();
        comments = new HashMap<CommandRegisterAddress, String>();
        final Iterable<? extends LSTLine> lines = source.getLines();

        CommandRegisterAddress lastNumber = CommandRegisterAddressImpl.createUnSafe(0);

        for (final LSTLine currentLine : lines) {
            final CommandRegisterAddress number = currentLine.getCommandRegisterNumber();
            if (number != null) {
                //TODO BOGUS
                lastNumber = currentLine.getCommandRegisterNumber();
                comments.put(number, currentLine.getComment());
            } else {
                if (comments.containsKey(lastNumber)) {
                    final String oldComment = comments.get(lastNumber);
                    final String newComment = oldComment + '\n' + currentLine.getComment();
                    comments.put(lastNumber, newComment);
                } else {
                    comments.put(lastNumber, currentLine.getComment());
                }
            }
        }
    }

    @Override
    public void setBreakPoint(int where, boolean doBreak) {
        log.debug("on " + where + "breakpoint is " + doBreak);
        if (doBreak) {
            breakPoints.add(where);
        } else {
            breakPoints.remove(where);
        }
    }

    @NotNull
    @Override
    public OpCodeGui getCommandAt(final int where) {

        final CommandRegisterAddress commandRegisterAddress = CommandRegisterAddressImpl.createUnSafe(
                where);
        final OpCode opCode = picMemory.getOpCodeAt(commandRegisterAddress);
        final String comment = comments.get(commandRegisterAddress);
        return new OpCodeGui() {

            @NotNull
            @Override
            public String getComments() {
                return comment != null ? comment : "nichts hinterlegt";
            }

            @Override
            public int getAddress() {
                return where;
            }

            @Override
            public boolean isCurrentAddress() {
                return getAddress() == getCurrentPos();
            }

            @Override
            public boolean hasBreakPoint() {
                return breakPoints.contains(where);
            }

            @Override
            public void setBreakPoint(boolean to) {
                CommandRegisterImpl.this.setBreakPoint(where, to);


            }

            @Override
            public Bits getData() {
                return opCode.getValue();
            }
        };
    }

    @Override
    public int getCurrentPos() {
        return programCounter.getCurrentValue().asInteger();
    }

    @Override
    public boolean isBreakPoint(int where) {
        return breakPoints.contains(where);
    }
}
